let g:count=0
"this type is used to indicat if the filter is normal or extend
let g:type="Normal"
function! s:FilterPattern(pattern)
    "get the word under the cursor
    let pattern = a:pattern
    if pattern == ''
        "let pattern = expand("<cword>")
        return
    endif
    "we should output the whole line, ignore the case
    let pattern = '.*' . '\c'.pattern . '.*'

    "save the current cursor position
    let save_cursor = getpos(".")

    let str=''
    normal gg
    while search(pattern, "W") > 0
        let str = str . getline('.') . "\n" 
    endwhile

    "restor the previous cursor position
    call setpos('.', save_cursor)


    let bufferName = "__filter"

    let hasExtendBuf=0
    "check whether has extend mode window
    let winCnt = winnr('$')

    if g:type == "Extend" 
        let index=1
        while 1
            if index > winCnt
                break
            endif
            if(bufname(winbufnr(index))==bufferName)
                let hasExtendBuf=1
                exe index . "wincmd w" 
                normal q
                "recalculate the windows count
                let winCnt = winnr('$')
                break
            endif

            let index=index+1
        endwhile
        "a extend mode, just use same default buffer name
        silent exe "bo vsplit " . bufferName
    else
        "every time call this, add the count
        let g:count=g:count+1
        "the buffer name is different cause count
        silent exe "bo vsplit " . bufferName . g:count 
    endif

    setlocal buftype=nofile
    "setlocal winfixwidth
    execute 'nnoremap <silent> <buffer> q :bd<cr>'
    execute 'nnoremap <silent> <buffer> Q :close<bar>wincmd p<cr>'

    silent put = str
    normal gg

    "move cursor to the original buffer window
    call feedkeys("\<C-W>t") 
    "move the original window as the top one
    call feedkeys("\<C-W>K") 
    "move cursor to the latest buffer window
    call feedkeys("\<C-W>b") 


    if g:type == "Extend" 
        "it's  extend mod, should move the buffer to the bottom-left
        if winCnt > 1
            call feedkeys("\<C-W>r") 
        endif

    endif

    call feedkeys("\<C-W>t") 

    echo pattern
    return 
endfunction

let g:pattern = ""
let g:patternExt = ""

"***********************************************************************
"* Function Name:FilterPattern(pattern)
"*         This function use the pattern that user input to filter the
"*         content. it would cover the previous filter pattern
"* ---------------------------------------------------------------------
"* 
"***********************************************************************
function! s:Filter(pattern)
    let g:pattern = a:pattern

    let g:type="Normal"
    call s:FilterPattern(g:pattern)

    return
endfunction


"***********************************************************************
"* Function Name:FilterExt(filter)
"*         This function add filter into the current filter pattern.
"* ---------------------------------------------------------------------
"* 
"***********************************************************************
function! s:FilterExt(filter)
    if g:patternExt == ""
        "no pattern, it's the first one, so work as normal
        let g:patternExt = a:filter
    else
        if a:filter!=""
            let g:patternExt = g:patternExt . '\|' . a:filter
        endif
    endif
    
    let g:type="Extend"
    call s:FilterPattern(g:patternExt)

    return
endfunction

"***********************************************************************
"* Function Name:FilterReExt(filter)
"*         This function clean current pattern and use filter as the new pattern
"* ---------------------------------------------------------------------
"* 
"***********************************************************************
function! s:FilterReExt(filter)

    let g:patternExt = a:filter
    
    let g:type="Extend"
    call s:FilterPattern(g:patternExt)

    return
endfunction

"*****************************************************************
"* DelToken : delete token from source 
"*----------------------------------------------------------------
"*   src : source
"*   dlm : delimiter
"*****************************************************************
function! s:DelToken(src,dlm, item)
  let tokn_spl=''    " token
  let tokn_all=a:src " all source

  if a:item == ''
      return a:src
  endif

  if a:src == ''
      return a:src
  endif

  let tokn_new=''

  "find all match item
  while 1
    let tokn_spl = strpart(tokn_all,0,stridx(tokn_all,a:dlm))
    if tokn_spl == ''
        "this is the last one
        let tokn_spl = tokn_all
    endif


    if tokn_spl != a:item
        "not match, we should reuse this token and continue check
        let tokn_new = tokn_new . tokn_spl . a:dlm
    endif

    "get the rest
    let tokn_all = strpart(tokn_all,strlen(tokn_spl.a:dlm))

    if tokn_all==''
        "match, don't need to find again 
        break
    endif

  endwhile

  "delete the last  delimiter
  let tokn_new = strpart(tokn_new, 0, strlen(tokn_new)-strlen(a:dlm))

  if tokn_new == ''
      let tokn_new = a:item 
  endif

  return tokn_new
endfunction
"***********************************************************************
"* Function Name:FilterDelExt(filter)
"*         This function delete filter that contained in the current filter pattern.
"* ---------------------------------------------------------------------
"* 
"***********************************************************************
function! s:FilterDelExt(filter)
    let g:patternExt = s:DelToken(g:patternExt, "\\|", a:filter)
    if g:patternExt == ""
        break
    endif
    
    let g:type="Extend"
    call s:FilterPattern(g:patternExt)

    return
endfunction

let g:n=0
function! s:FilterColor(pattern, color)
    if a:pattern == ""
        return
    endif

    if a:color == ""
        return
    endif

    let g:n=g:n+1
    let color = tolower(a:color)
    "should ignore the case
    let pattern = "\.\*"."\\c".a:pattern ."\.\*"

    let group= "grp_" . color 


    if str2nr(a:color) !=0
        if a:color == "1"
            let color = "red"
        elseif a:color == "2"
            let color = "green"
        elseif a:color == "3"
            let color = "yellow"
        elseif a:color == "4"
            let color = "magenta"
        elseif a:color == "5"
            let color = "blue"
        elseif a:color == "6"
            let color = "cyan"
        elseif a:color == "7"
            let color = "lightred"
        elseif a:color == "8"
            let color = "lightgreen"
        elseif a:color == "9"
            let color = "lightyellow"
        elseif a:color == "10"
            let color = "lightmagenta"
        elseif a:color == "11"
            let color = "lightblue"
        elseif a:color == "12"
            let color = "lightcyan"
        endif
    else
        let color = a:color
    endif

    if a:color != ""
        execute "hi ".group." guifg=".color
    endif

    let m=matchadd(group, pattern)

endfunction

command Filter :call <SID>Filter(input("input pattern:"))
command FilterExt :call <SID>FilterExt(input("input filter:"))
command FilterDelExt :call <SID>FilterDelExt(input("input delete filter:"))
command FilterReExt :call <SID>FilterReExt(input("input new filter:"))
command FilterColor :call <SID>FilterColor(input("input pattern:"), input("input color:"))

"filter parttern for call:
" .*\(callapp\|callmanageapp\|ecall:\|acncall:\|servicecall:\).*
command FilterCall :call <SID>Filter("callapp\\|callmanageapp\\|ecall:\\|acncall:\\|servicecall:")
command FilterECall :call <SID>Filter("callapp\\|callmanageapp\\|ecall:")
command FilterACNCall :call <SID>Filter("callapp\\|callmanageapp\\|acncall:")
command FilterServiceCall :call <SID>Filter("callapp\\|callmanageapp\\|servicecall:")

"map for output filter result
noremap <silent> <F10> :Filter<CR>
imap <F10> <Esc>:Filter<CR>
noremap <F9> :FilterExt<CR>
imap <F9> <Esc>:FilterExt<CR>
"map for  color the filter
noremap <F11> :FilterColor<CR>

noremap <C-F9> :FilterDelExt<CR>
noremap <S-F9> :FilterReExt<CR>
